home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / octa209s.zip / octave-2.09 / libs / kpathsea / tex-make.c < prev    next >
C/C++ Source or Header  |  1996-11-02  |  10KB  |  330 lines

  1. /* tex-make.c: Run external programs to make TeX-related files.
  2.  
  3. Copyright (C) 1993, 94 Karl Berry.
  4.  
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.  */
  18.  
  19. #include <kpathsea/config.h>
  20.  
  21. #include <kpathsea/c-fopen.h>
  22. #include <kpathsea/c-pathch.h>
  23. #include <kpathsea/concatn.h>
  24. #include <kpathsea/db.h>
  25. #include <kpathsea/fn.h>
  26. #include <kpathsea/magstep.h>
  27. #include <kpathsea/readable.h>
  28. #include <kpathsea/tex-make.h>
  29. #include <kpathsea/variable.h>
  30.  
  31.  
  32. /* We never throw away stdout, since that is supposed to be the filename
  33.    found, if all is successful.  This variable controls whether stderr
  34.    is thrown away.  */
  35. boolean kpse_make_tex_discard_errors = false;
  36.  
  37. /* We set the envvar MAKETEX_MAG, which is part of the default spec for
  38.    MakeTeXPK above, based on KPATHSEA_DPI and MAKETEX_BASE_DPI.  */
  39.  
  40. static void
  41. set_maketex_mag P1H(void)
  42. {
  43.   char q[MAX_INT_LENGTH * 3 + 3];
  44.   int m;
  45.   string dpi_str = getenv ("KPATHSEA_DPI");
  46.   string bdpi_str = getenv ("MAKETEX_BASE_DPI");
  47.   unsigned dpi = dpi_str ? atoi (dpi_str) : 0;
  48.   unsigned bdpi = bdpi_str ? atoi (bdpi_str) : 0;
  49.  
  50.   /* If the environment variables aren't set, it's a bug.  */
  51.   assert (dpi != 0 && bdpi != 0);
  52.   
  53.   /* Fix up for roundoff error.  Hopefully the driver has already fixed
  54.      up DPI, but may as well be safe, and also get the magstep number.  */
  55.   (void) kpse_magstep_fix (dpi, bdpi, &m);
  56.   
  57.   /* Have to do something different for DOS?  */
  58. #if defined (DOS) || defined (OS2)
  59.   {
  60.     int n;
  61.     double t;
  62.  
  63.     if (m == 0)  t = (double)dpi/bdpi;
  64.     else
  65.       {
  66.     if (m < 0)  n = -m;
  67.     else        n = m;
  68.     if (n & 1)
  69.       {
  70.             n &= ~1;
  71.             t = 1.095445115;
  72.       }
  73.     else  t = 1.0;
  74.  
  75.     while (n > 0)
  76.       {
  77.             n -= 2;
  78.             t = t * 1.2;
  79.       }
  80.     if (m < 0)  t = 1 / t;
  81.       }
  82.     sprintf(q, "%12.9f", t);
  83.   }
  84. #else
  85.   if (m == 0)
  86.     sprintf (q, "%d+%d/%d", dpi / bdpi, dpi % bdpi, bdpi);
  87.   else
  88.     { /* m is encoded with LSB being a ``half'' bit (see magstep.h).  Are
  89.          we making an assumption here about two's complement?  Probably.
  90.          In any case, if m is negative, we have to put in the sign
  91.          explicitly, since m/2==0 if m==-1.  */
  92.       const_string sign = "";
  93.       if (m < 0)
  94.         {
  95.           m *= -1;
  96.           sign = "-";
  97.         }
  98.       sprintf (q, "magstep\\(%s%d.%d\\)", sign, m / 2, (m & 1) * 5);
  99.     } 
  100. #endif 
  101.   xputenv ("MAKETEX_MAG", q);
  102. }
  103.  
  104. /* This MakeTeX... program was disabled, or the script failed.  If this
  105.    was a font creation (according to FORMAT), append CMD
  106.    to a file missfont.log in the current directory.  */
  107.  
  108. static void
  109. misstex P2C(kpse_file_format_type, format,  const_string, cmd)
  110. {
  111.   static FILE *missfont = NULL;
  112.  
  113.   /* If we weren't trying to make a font, do nothing.  Maybe should
  114.      allow people to specify what they want recorded?  */
  115.   if (format > kpse_any_glyph_format && format != kpse_tfm_format
  116.       && format != kpse_vf_format)
  117.     return;
  118.  
  119.   /* If this is the first time, have to open the log file.  */
  120.   if (!missfont)
  121.     {
  122.       const_string missfont_name = "missfont.log";
  123.       missfont = fopen (missfont_name, FOPEN_A_MODE);
  124.       if (!missfont && getenv ("TEXMFOUTPUT"))
  125.         {
  126.           missfont_name = concat3 (getenv ("TEXMFOUTPUT"), DIR_SEP_STRING,
  127.                                    missfont_name);
  128.           missfont = fopen (missfont_name, FOPEN_A_MODE);
  129.         }
  130.  
  131.       /* Should we really be unconditionally shouting this message?  */
  132.       if (missfont)
  133.         fprintf (stderr, "kpathsea: Appending font creation commands to %s.\n",
  134.                  missfont_name);
  135.     }
  136.   
  137.   /* Write the command if we have a log file.  */
  138.   if (missfont)
  139.     {
  140.       fputs (cmd, missfont);
  141.       putc ('\n', missfont);
  142.     }
  143. }  
  144.  
  145.  
  146. /* Assume the script outputs the filename it creates (and nothing
  147.    else) on standard output; hence, we run the script with `popen'.  */
  148.  
  149. static string
  150. maketex P2C(kpse_file_format_type, format,  const_string, cmd)
  151. {
  152.   string ret;
  153.   FILE *f;
  154.   
  155.   /* Tell the user we are running the script, so they have a clue as to
  156.      what's going on if something messes up.  */
  157.   fprintf (stderr, "kpathsea: Running %s\n", cmd);
  158.   
  159.   /* Run the script.  */
  160.   f = popen (cmd, FOPEN_R_MODE);
  161.  
  162.   if (f)
  163.     {
  164.       int c;
  165.       string fn;             /* The final filename.  */
  166.       unsigned len;          /* And its length.  */
  167.       fn_type output;
  168.       output = fn_init ();   /* Collect the script output.  */
  169.  
  170.       /* Read all the output and terminate with a null.  */
  171.       while ((c = getc (f)) != EOF)
  172.         fn_1grow (&output, c);
  173.       fn_1grow (&output, 0);
  174.  
  175.       /* Maybe should check for `EXIT_SUCCESS' status before even
  176.          looking at the output?  */
  177.       if (pclose (f) == -1)
  178.         FATAL_PERROR (cmd);
  179.  
  180.       len = FN_LENGTH (output);
  181.       fn = FN_STRING (output);
  182.  
  183.       /* Remove trailing newlines and returns.  */
  184.       while (len > 1 && (fn[len - 2] == '\n' || fn[len - 2] == '\r'))
  185.         {
  186.           fn[len - 2] = 0;
  187.           len--;
  188.         }
  189.  
  190.       /* If no output from script, return NULL.  Otherwise check
  191.          what it output.  */
  192.       ret = len == 1 ? NULL : kpse_readable_file (fn);
  193.  
  194.       /* Free the name if we're not returning it.  */
  195.       if (fn != ret)
  196.         free (fn);
  197.     }
  198.   else
  199.     /* popen failed.  Maybe should give error (optionally), but for
  200.        now be silent, to avoid annoying people who purposefully
  201.        don't have the script installed. */
  202.     ret = NULL;
  203.   
  204.   if (ret == NULL)
  205.     misstex (format, cmd);
  206.   else
  207.     db_insert (ret);
  208.     
  209.   return ret;
  210. }
  211.  
  212.  
  213. /* Create BASE in FORMAT and return the generated filename, or
  214.    return NULL.  */
  215.  
  216. string
  217. kpse_make_tex P2C(kpse_file_format_type, format,  const_string, base)
  218. {
  219.   kpse_format_info_type spec; /* some compilers lack struct initialization */
  220.   string ret = NULL;
  221.   
  222.   spec = kpse_format_info[format];
  223.   
  224.   if (spec.program)
  225.     {
  226.       /* See the documentation for the envvars we're dealing with here.  */
  227.       string args, cmd;
  228.       const_string prog = spec.program; /* MakeTeXPK */
  229.       string PROG = uppercasify (prog); /* MAKETEXPK */
  230.       string progenv = getenv (PROG);   /* ENV{"MAKETEXPK"} */
  231.       const_string arg_spec = progenv ? progenv : spec.program_args;
  232.       string mode = getenv ("MAKETEX_MODE");
  233.       boolean unset_mode = false;
  234.       
  235.       set_maketex_mag ();
  236.       
  237.       /* Here's an awful kludge: if the mode is `/', unset it for the
  238.          call and then reset it.  We could ignore a mode of / in
  239.          MakeTeXPK, but then everyone's MakeTeXPK would have to handle
  240.          that special case, which seems too onerous.  `kpse_prog_init'
  241.          sets it to this in the first place when no mode is otherwise
  242.          specified; this is so when the user defines a resolution, they
  243.          don't also have to specify a mode; instead, MakeTeXPK's guesses
  244.          will take over.  They use / for the value because then when it
  245.          is expanded as part of the PKFONTS et al. path values, we'll
  246.          wind up searching all the pk directories.  We put $MAKETEX_MODE
  247.          in the path values in the first place so that sites with two
  248.          different devices with the same resolution can find the right
  249.          fonts; but such sites are uncommon, so they shouldn't make
  250.          things harder for everyone else.  */
  251.       if (mode && STREQ (mode, DIR_SEP_STRING))
  252.         {
  253.           xputenv ("MAKETEX_MODE", "");
  254.           unset_mode = true;
  255.         }
  256.       args = arg_spec ? kpse_var_expand (arg_spec) : (string) "";
  257.       if (unset_mode)
  258.         xputenv ("MAKETEX_MODE", DIR_SEP_STRING);
  259.       
  260.       /* The command is the program name plus the arguments.  */
  261.       cmd = concatn (prog, " ", base, " ", args, NULL);
  262.  
  263.       if (spec.program_enabled_p)
  264.         {
  265.           /* Only way to discard errors is redirect stderr inside another
  266.              shell; otherwise, if the MakeTeX... script doesn't exist, we
  267.              will see the `sh: MakeTeX...: not found' error.  No point in
  268.              doing this if we're not actually going to run anything.  */
  269.           if (kpse_make_tex_discard_errors)
  270.             {
  271.               string old_cmd = cmd;
  272.               cmd = concat3 ("sh -c \"", cmd, "\" 2>/dev/null");
  273.               free (old_cmd);
  274.             }
  275.  
  276.           ret = maketex (format, cmd);
  277.         }
  278.       else
  279.         misstex (format, cmd);
  280.  
  281.       free (PROG);
  282.       free (cmd);
  283.       if (*args)
  284.         free (args);
  285.     }  
  286.  
  287.   return ret;
  288. }
  289.  
  290. #ifdef TEST
  291.  
  292. void
  293. test_make_tex (kpse_file_format_type fmt, const_string base)
  294. {
  295.   string answer;
  296.   
  297.   printf ("\nAttempting %s in format %d:\n", base, fmt);
  298.  
  299.   answer = kpse_make_tex (fmt, base);
  300.   puts (answer ? answer : "(null)");
  301. }
  302.  
  303.  
  304. int
  305. main ()
  306. {
  307.   xputenv ("KPATHSEA_DPI", "781"); /* call MakeTeXPK */
  308.   xputenv ("MAKETEX_BASE_DPI", "300"); /* call MakeTeXPK */
  309.   KPSE_MAKE_SPEC_ENABLED (kpse_make_specs[kpse_pk_format]) = true;
  310.   test_make_tex (kpse_pk_format, "cmr10");
  311.  
  312.   /* Fail with MakeTeXTFM.  */
  313.   KPSE_MAKE_SPEC_ENABLED (kpse_make_specs[kpse_tfm_format]) = true;
  314.   test_make_tex (kpse_tfm_format, "foozler99");
  315.   
  316.   /* Call something disabled.  */
  317.   test_make_tex (kpse_bst_format, "no-way");
  318.   
  319.   return 0;
  320. }
  321.  
  322. #endif /* TEST */
  323.  
  324.  
  325. /*
  326. Local variables:
  327. test-compile-command: "gcc -g -I. -I.. -DTEST tex-make.c kpathsea.a"
  328. End:
  329. */
  330.